console.inspectEnable = true;
import WebApp from 'webapp';
import { ICallBack } from './interfaces/api.interface';
import { SocketServer } from './libs/socket_server';
import { GAS_DEFAULT_ALARM_VALUES } from './data/const';
import devManager from './libs/sddc_device';
import db from './data/lkv_db';
import { ISimpleDevice } from './libs/sddc_device/type';
const app = WebApp.createApp();
app.use(WebApp.static('./public'));

// 场景设备对象
const times = {};

const server = new SocketServer(app);
server.on('connection', (socket) => {
  socket.on('disconnect', () => {
    console.error('disconnect');
  });

  /* 应用初始化 */
  socket.on('init', () => {
    init();
  });

  /* 添加场景设备 */
  socket.on('add-scene-device', (devid: string) => {
    addSceneDevice(devid, socket);
  });

  /* 删除场景设备 */
  socket.on('delete-scene-device', (devid: string) => {
    deleteSceneDevice(devid);
  });

  /* 控制设备 */
  socket.on('send-device-info', (devid: string, data: any, cb: ICallBack) => {
    devManager.sendDeviceInfo(devid, data).catch((err) => {
      server.emitMessage('error', err);
    });
    // 设置警告值（气体浓度超过警告值会主动上报，因为这边已经有定时获取气体浓度了，所以是否设置成功结果不是必要）
    const dev = devManager.getDevice(devid);
    if (dev) {
      if (dev.brand === 'lgzm' && dev.type !== 'window') {
        // 气体设备设置警告值
        try {
          db.devs = db.devs.map((item) => {
            if (item.devid === devid) {
              return {
                ...item,
                settings: {
                  alarm_value: data[dev.type]
                }
              };
            }
            return item;
          });
          server.emitMessage('alarm', { devid, value: data[dev.type] });
          cb({ result: true, message: '操作成功！' });
        } catch (error) {
          console.error(error);
        }
      }
    } else {
      cb({ result: false, message: '未找到指定设备信息，请退出重置！' });
    }
  });
});

// 初始化应用前端数据
function init() {
  server.emitMessage('devices', devManager.getDeviceList());
  initScene();
}

// 初始化场景
function initScene() {
  for (const {
    devid,
    settings: { alarm_value, window_percent }
  } of db.devs) {
    const dev = devManager.getDevice(devid);
    if (!dev) {
      // 说明设备被删除 或者 不在线
      continue;
    }
    generateDevController(devid)
      .then(() => {
        if (dev.brand === 'lgzm' && dev.type === 'window') {
          // 开窗器
          server.emitMessage('join', { ...dev, real_value: window_percent });
        } else {
          // 气体
          server.emitMessage('join', { ...dev, real_value: 0, alarm_value });
        }
      })
      .catch(() => {
        console.error('generateDevController error.');
      });
  }
}

// 添加场景设备
function addSceneDevice(devid: string, socket: any) {
  const dev = devManager.getDevice(devid);
  if (!dev) {
    server.emitRoomMessage(socket.id, 'error', '设备不存在，请检查重试！');
  }
  generateDevController(devid)
    .then(() => {
      if (!dev.type) {
        server.emitRoomMessage(socket.id, 'error', '设备类型或型号错误！');
      }
      if (dev.type === 'window') {
        // 窗户
        db.devs = [...(db.devs || []), { devid, settings: { window_percent: 0 } }];
        server.emitMessage('join', { ...dev, real_value: 0 });
        return;
      }
      // 气体设备
      try {
        db.devs = [...(db.devs || []), { devid, settings: { alarm_value: GAS_DEFAULT_ALARM_VALUES[dev.type] } }];
        server.emitMessage('join', { ...dev, real_value: 0, alarm_value: GAS_DEFAULT_ALARM_VALUES[dev.type] });
        // 重置气体设定警告值
        const data = { method: 'set' };
        data[dev.type] = GAS_DEFAULT_ALARM_VALUES[dev.type];
        devManager.sendDeviceInfo(devid, data).catch(() => {
          server.emitRoomMessage(socket.id, 'error', `初始化${dev.alias}设备警告值失败！`);
        });
      } catch (error) {
        console.error(error);
      }
    })
    .catch((err) => {
      server.emitRoomMessage(socket.id, 'error', err);
    });
}

// 删除场景设备
function deleteSceneDevice(devid: string) {
  try {
    db.devs = db.devs.filter((item) => {
      return item.devid !== devid;
    });
    devManager.destroyController(devid);
    clearInterval(times[devid]);
    times[devid] = undefined;
    server.emitMessage('delete', devManager.getDevice(devid));
  } catch (error) {
    console.error(error);
  }
}

// 构建设备控制对象
function generateDevController(devid: string) {
  if (devManager.getController(devid)) {
    initDeviceValue(devid);
    return Promise.resolve(devManager.getController(devid));
  }
  return new Promise((resolve, reject) => {
    const dev = devManager.getDevice(devid);
    if (!dev) {
      return reject('no device.');
    }
    devManager
      .generateController(devid)
      .then((controller) => {
        controller.on('message', ({ data }) => {
          // 开窗器需要记录当前位置
          if (dev.brand === 'lgzm' && dev.type === 'window') {
            server.emitMessage('message', { devid, data: data.window_percent });
            try {
              db.devs = db.devs.map((item) => {
                if (item.devid === devid) {
                  return {
                    ...item,
                    settings: {
                      window_percent: data['window_percent']
                    }
                  };
                }
                return item;
              });
            } catch (error) {
              console.error(error);
            }
          } else {
            server.emitMessage('message', { devid, data: data[dev.type] });
            const curDevInfo = db.devs.find((item) => item.devid === devid);
            if (curDevInfo && typeof curDevInfo.settings.alarm_value === 'number') {
              if (curDevInfo.settings.alarm_value < data[dev.type]) {
                // 气体超标 找到窗户设备
                const window_dev = db.devs.find((item) => {
                  const d = devManager.getDevice(item.devid);
                  if (d && d.brand === 'lgzm' && d.type === 'window') {
                    return true;
                  }
                  return false;
                });
                if (window_dev) {
                  console.warn(`Gas [${dev.type}] concentration exceeds the standard, opening the window...`)
                  devManager.sendDeviceInfo(window_dev.devid, { method: 'set', window: 'right' }).catch(() => {
                    console.error(`Failed to open window value.`);
                  });
                }
              }
            }
          }
        });
        initDeviceTimer(devid);
        initDeviceValue(devid);
        resolve(controller);
      })
      .catch(() => {
        reject(`no permission.`);
        // emitError(`应用缺少控制${dev.alias}的权限！`)
      });
  });
}

function initDeviceValue(devid: string) {
  const { brand, type } = devManager.getDevice(devid) || {};
  if (brand === 'lgzm' && type === 'window') {
    // 开窗器
    const d = db.devs.find((item) => item.devid === devid);
    if (d) {
      devManager.sendDeviceInfo(devid, { method: 'set', window_percent: d.settings.window_percent || 0 });
    }
  }
}

function initDeviceTimer(devid: string) {
  const { brand, type } = devManager.getDevice(devid) || {};
  if (brand === 'lgzm' && type !== 'window') {
    // 气体
    clearInterval(times[devid]);
    times[devid] = undefined;
    times[devid] = setInterval(() => {
      devManager.sendDeviceInfo(devid, { method: 'get', obj: [type] }).catch(() => {
        console.error(`Failed to get ${type} real-time value.`);
      });
    }, 3000);
  }
}

/* 设备上线 */
devManager.on('join', (dev: ISimpleDevice) => {
  server.emitMessage('deviceList', devManager.getDeviceList());
  const scene_dev = db.devs.find((item) => {
    return item.devid === dev.devid;
  });
  if (scene_dev) {
    generateDevController(dev.devid)
      .then(() => {
        if (dev.brand === 'lgzm' && dev.type === 'window') {
          // 开窗器
          server.emitMessage('join', { ...dev, real_value: scene_dev.settings.window_percent });
        } else {
          // 气体
          server.emitMessage('join', { ...dev, real_value: 0, alarm_value: scene_dev.settings.alarm_value });
        }
      })
      .catch((err) => {
        console.error(err);
      });
  }
});

/* 设备下线  */
devManager.on('lost', (dev) => {
  server.emitMessage('deviceList', devManager.getDeviceList());
  if (isSceneDev(dev.devid)) {
    clearInterval(times[dev.devid]);
    times[dev.devid] = undefined;
    server.emitMessage('lost', dev);
  }
});

// 是否是场景设备
function isSceneDev(devid: string) {
  return db.devs.findIndex((item) => item.devid === devid) >= 0;
}

app.start();
require('iosched').forever();
